import Web3 from "web3";
import { useEffect, useState } from "react";
import "./style.css";

const EthBack = () => {
  const web3 = new Web3("ws://127.0.0.1:7545");
  const [bankMoney, setBankMoney] = useState("0");
  const [userBankMoney, setUserBankMoney] = useState("0");
  const [userMoney, setUserMoney] = useState("0");
  const [userAddress, setUserAddress] = useState(
    "0xD0fE682b0524a160fbe09E31C861b169D9D9Ca03"
  );
  const [privateKey, setPrivateKey] = useState(
    "0x40b50aaa22469329e341f243bae91da13439f960c7be96569283814e9f9223bb"
  );
  const [ck_money, ck_setMoney] = useState("");
  const [qk_money, qk_setMoney] = useState("");

  const [toUserAddress, setToUserAddress] = useState("");
  const [toMoney, setToMoney] = useState("");

  // ====== 合约数据 =======
  const contractAddress = "0x1c19c4a5ec0115eeaCD8a5E0Ae11bE0c7b1D4504";
  const contractAbi = [
    {
      type: "function",
      name: "deposit",
      inputs: [],
      outputs: [],
      stateMutability: "payable"
    },
    {
      type: "function",
      name: "deposits",
      inputs: [{ name: "", type: "address", internalType: "address" }],
      outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
      stateMutability: "view"
    },
    {
      type: "function",
      name: "queryUserMoney",
      inputs: [],
      outputs: [{ name: "", type: "uint256", internalType: "uint256" }],
      stateMutability: "view"
    },
    {
      type: "function",
      name: "withdraw",
      inputs: [{ name: "amount", type: "uint256", internalType: "uint256" }],
      outputs: [],
      stateMutability: "nonpayable"
    },
    {
      type: "event",
      name: "Deposit",
      inputs: [
        {
          name: "user",
          type: "address",
          indexed: true,
          internalType: "address"
        },
        {
          name: "amount",
          type: "uint256",
          indexed: false,
          internalType: "uint256"
        }
      ],
      anonymous: false
    },
    {
      type: "event",
      name: "Withdraw",
      inputs: [
        {
          name: "user",
          type: "address",
          indexed: true,
          internalType: "address"
        },
        {
          name: "amount",
          type: "uint256",
          indexed: false,
          internalType: "uint256"
        }
      ],
      anonymous: false
    }
  ];

  // 使用 useEffect 确保 web3.eth.net.isListening 只在组件加载时执行一次
  useEffect(() => {
    web3.eth.net
      .isListening()
      .then(async (res) => {
        await queryBankMoney();
        await queryUserBankMoney();
        await queryMoney();
        console.log("is ok =>", res);
      })
      .catch((err) => {
        console.log("no create err =>", err);
      });
  }, []); // 空依赖数组，确保只执行一次

  // 创建合约对象
  const contract = new web3.eth.Contract(contractAbi, contractAddress);

  // 事件监听
  const go1 = async () => {
    const resDeposit = await contract.events.Deposit({ fromBlock: "latest" });
    resDeposit.on("data", (event) => {
      console.log("resDeposit data event =>", event);
    });

    resDeposit.on("error", (event) => {
      console.log("resDeposit error event =>", event);
    });

    const resWithdraw = await contract.events.Withdraw({ fromBlock: "latest" });
    resWithdraw.on("data", (event) => {
      console.log("resWithdraw data event =>", event);
    });

    resWithdraw.on("error", (event) => {
      console.log("resWithdraw error event =>", event);
    });
  };

  useEffect(() => {
    go1();
  }, []);

  // 清除数据
  const clearData = async () => {
    setUserBankMoney("0");
    setUserMoney("0");
    ck_setMoney("");
    qk_setMoney("");
    setUserAddress("");
    setPrivateKey("");
  };

  // 查询余额
  const queryMoney = async () => {
    if (userAddress === "") return;
    try {
      const balance = await web3.eth.getBalance(userAddress);
      setUserMoney(`${web3.utils.fromWei(balance, "ether")} ether`);
    } catch (err) {
      console.log("queryMoney =>", err);
    }
  };

  // 查询银行的钱
  const queryBankMoney = async () => {
    try {
      const balance = await web3.eth.getBalance(contractAddress);
      setBankMoney(`${web3.utils.fromWei(balance, "ether")} ether`);
    } catch (err) {
      console.log("queryMoney =>", err);
    }
  };

  // 查询用户在银行存 多少钱
  const queryUserBankMoney = async () => {
    try {
      const balance = await contract.methods
        .queryUserMoney()
        .call({ from: userAddress });
      setUserBankMoney(`${web3.utils.fromWei(balance, "ether")} ether`);
    } catch (err) {
      console.log("queryUserBankMoney err =>", err);
    }
  };

  // 用户存款
  const deposits = async () => {
    if (ck_money === "") return;

    const gasPrice = await web3.eth.getGasPrice(); // 获取当前网络的 gas 价格
    const data_ck_gas = contract.methods.deposit().encodeABI();

    // 预估 gas
    const gasEstimate = await web3.eth.estimateGas({
      from: userAddress,
      to: contractAddress,
      data: data_ck_gas
    });

    const tx = {
      from: userAddress,
      to: contractAddress,
      gas: gasEstimate + BigInt(100000),
      gasPrice: gasPrice,
      value: web3.utils.toWei(ck_money, "ether"), // 转换为 wei 单位
      data: data_ck_gas
    };

    const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey); // 签署交易

    web3.eth
      .sendSignedTransaction(signedTx.rawTransaction)
      .on("receipt", () => {
        queryBankMoney();
        queryUserBankMoney();
        queryMoney();
      });
  };

  // 用户取钱
  const withdraw = async () => {
    if (qk_money === "") return;
    // 1.查询账户余额
    await queryMoney();
    if (Number(userMoney) <= 0 || Number(qk_money) <= Number(userMoney)) {
      return alert("余额不足");
    }

    try {
      const gasPrice = await web3.eth.getGasPrice(); // 2.1 获取当前网络的 gas 价格
      const hy_data = await contract.methods
        .withdraw(web3.utils.toWei(qk_money, "ether"))
        .encodeABI(); // 合约 数据

      // 2.1 估算 gas
      const gasEstimate = await web3.eth.estimateGas({
        from: userAddress,
        to: contractAddress,
        data: hy_data
      });

      // 交易信息
      const tx = {
        from: userAddress,
        to: contractAddress,
        value: "",
        gas: gasEstimate,
        gasPrice: gasPrice,
        data: hy_data
      };

      // 3.离线 签名交易
      const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);

      // 4.广播区块链
      web3.eth
        .sendSignedTransaction(signedTx.rawTransaction)
        .on("receipt", () => {
          queryBankMoney();
          queryUserBankMoney();
          queryMoney();
        });
    } catch (err) {
      console.log("withdraw err =>", err);
    }
  };

  // 用户转账
  const userTransferToUser = async () => {
    if (toUserAddress === "" || toMoney === "") return;

    try {
      const gasPrice = await web3.eth.getGasPrice(); // 2.1 获取当前网络的 gas 价格

      // 交易信息
      const tx = {
        from: userAddress,
        to: toUserAddress,
        value: web3.utils.toWei(toMoney, "ether"), // ether 转 wei
        gas: 21000,
        gasPrice: gasPrice
      };

      // 3.离线 签名交易
      const signedTx = await web3.eth.accounts.signTransaction(tx, privateKey);

      // 4.广播区块链
      web3.eth
        .sendSignedTransaction(signedTx.rawTransaction)
        .on("receipt", () => {
          queryMoney();
          alert(`转账成功 金额为 ${toMoney} ether!`);
        });
    } catch (err) {
      console.log("withdraw err =>", err);
    }
  };

  return (
    <div className="app">
      <div className="flex-center wallet-title">
        <p>- Contract Bank - </p>
      </div>

      <div>
        <p>BankMoney ALL: {bankMoney}</p>
      </div>

      <div>
        <p>user BankMoney: {userBankMoney}</p>
      </div>

      <div className="pd-5">
        <span>user Money:{userMoney} &nbsp;</span>
        <button type="button" onClick={queryMoney}>
          query My Money
        </button>
      </div>

      <div className="pd-5">
        <span>user Address:</span>
        <input
          value={userAddress}
          onChange={(e) => setUserAddress(e.target.value)}
          placeholder="Address"
        ></input>
        <button
          type="button"
          onClick={() => {
            setUserAddress("");
            clearData();
          }}
        >
          clear
        </button>
      </div>

      <div className="pd-5">
        <span>user PrivateKey:</span>
        <input
          value={privateKey}
          onChange={(e) => setPrivateKey(e.target.value)}
          placeholder="privateKey"
          style={{ width: "160px" }}
        ></input>
        <button
          type="button"
          onClick={() => {
            setPrivateKey("");
            clearData();
          }}
        >
          clear
        </button>
      </div>

      {/* <br></br>
      <div className="box-x">
        <p>on Event</p>
        <button type="button" onClick={go1}>
          go1
        </button>
      </div> */}
      <br></br>

      <div className="box-x">
        <p>user Save Money</p>
        <input
          value={ck_money}
          onChange={(e) => ck_setMoney(e.target.value)}
          placeholder="Money"
        ></input>
        <button type="button" onClick={deposits}>
          go2
        </button>
      </div>

      <div className="box-x">
        <p>user Draw Money</p>
        <input
          value={qk_money}
          onChange={(e) => qk_setMoney(e.target.value)}
          placeholder="Money"
        ></input>
        <button type="button" onClick={withdraw}>
          go3
        </button>
      </div>

      <div className="flex-box">
        <button type="button" onClick={clearData}>
          clear Data
        </button>

        <button
          type="button"
          onClick={() => {
            queryBankMoney();
            queryUserBankMoney();
            queryMoney();
          }}
        >
          Updata
        </button>
      </div>

      <div>
        <div className="flex-center wallet-title">
          <p>- User Transfer - </p>
        </div>

        <div className="wallet-fun">
          <button type="button">Send</button>
        </div>

        <div className="wallet-send">
          <textarea
            value={toUserAddress}
            onChange={(e) => setToUserAddress(e.target.value)}
            placeholder="address"
            className="wallet-address-tx"
          ></textarea>
          <input
            placeholder="toMoney"
            value={toMoney}
            onChange={(e) => setToMoney(e.target.value)}
          ></input>{" "}
          <button type="button" onClick={userTransferToUser}>
            Send OK
          </button>
        </div>

        <div style={{ height: "50px" }}></div>
      </div>
    </div>
  );
};

export default EthBack;
